#include <Windows.h>
#include <Psapi.h>
#include <string>
#include <iostream>
using namespace std;


#ifdef _DEBUG
char dllname[] = "../Win32/Debug/FirefoxHandler.dll";
#else
char dllname[] = "../Win32/Release/FirefoxHandler.dll";
#endif // _DEBUG

HMODULE kernel32;
void *loadAddr;
void *freeAddr;

void detach(DWORD id)
{
    HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, false, id);
    if (!process)
    {
        cout << "access denied!" << endl;
        return;
    }

    SIZE_T dd;


    void *lpdllname = VirtualAllocEx(process, nullptr, sizeof(dllname), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    if (lpdllname != nullptr)
    {
        WriteProcessMemory(process, lpdllname, dllname, sizeof(dllname), &dd);

        HANDLE thread;
        thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)loadAddr, lpdllname, 0, &dd);
        if (thread == INVALID_HANDLE_VALUE)
            return;
        WaitForSingleObject(thread, -1);

        DWORD base;
        GetExitCodeThread(thread, &base);

        thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)freeAddr, (LPVOID)base, 0, &dd);
        if (thread == INVALID_HANDLE_VALUE)
            return;
        WaitForSingleObject(thread, -1);
        thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)freeAddr, (LPVOID)base, 0, &dd);
        if (thread == INVALID_HANDLE_VALUE)
            return;
        WaitForSingleObject(thread, -1);
    }

}

std::string processName(DWORD id)
{
    HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, id);
    if (process)
    {
        char name[1024];
        DWORD len = sizeof(name);
        if (QueryFullProcessImageNameA(process, 0, name, &len))
            return name;
    }
    return "";
}

int main()
{
    kernel32 = LoadLibraryA("kernel32");
    if (kernel32 == 0)
        return 1;
    loadAddr = GetProcAddress(kernel32, "LoadLibraryA");
    if (loadAddr == 0)
        return 1;
    freeAddr = GetProcAddress(kernel32, "FreeLibrary");
    if (freeAddr == 0)
        return 1;


    DWORD dd = 1024 * sizeof(DWORD);
    DWORD *ids = new DWORD[dd / sizeof(DWORD)];
    EnumProcesses(ids, dd, &dd);

    for (DWORD i = 0; i < dd / sizeof(DWORD); i++)
    {
        auto id = ids[i];
        if (processName(id).find("\\e.exe") != string::npos)
            detach(id);
    }

}